]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
dnd: Implement touch event support
authorCarlos Garnacho <carlosg@gnome.org>
Fri, 16 Oct 2015 16:28:11 +0000 (18:28 +0200)
committerCarlos Garnacho <carlosg@gnome.org>
Fri, 4 Dec 2015 10:50:13 +0000 (11:50 +0100)
We need to keep track of the pointer emulating touch sequence. In order
to have events properly redirected on touch devices, the
Clutter.grab_pointer and ungrab_pointer() have been replaced by the grab()
and grab_sequence() ClutterInputDevice methods, one or the other is used
depending on the device triggering DnD.

An extra "sequence" argument has been added to startDrag, passing null here
will resort to pointer grabs.

This is enough to make thumbnails in the WorkspaceBox draggable through
touch.

https://bugzilla.gnome.org/show_bug.cgi?id=756748

js/ui/dnd.js

index 2b872419cf4dc87ef91735671d97e7a8078c055f..c7140a1c2468a74217b5b8b78c3eca5cbf4b76ff 100644 (file)
@@ -79,9 +79,12 @@ const _Draggable = new Lang.Class({
                                         dragActorOpacity: undefined });
 
         this.actor = actor;
-        if (!params.manualMode)
+        if (!params.manualMode) {
             this.actor.connect('button-press-event',
                                Lang.bind(this, this._onButtonPress));
+            this.actor.connect('touch-event',
+                               Lang.bind(this, this._onTouchEvent));
+        }
 
         this.actor.connect('destroy', Lang.bind(this, function() {
             this._actorDestroyed = true;
@@ -121,8 +124,50 @@ const _Draggable = new Lang.Class({
         return Clutter.EVENT_PROPAGATE;
     },
 
+    _onTouchEvent: function (actor, event) {
+        if (event.type() != Clutter.EventType.TOUCH_BEGIN ||
+            !global.display.is_pointer_emulating_sequence(event.get_event_sequence()))
+            return Clutter.EVENT_PROPAGATE;
+
+        if (Tweener.getTweenCount(actor))
+            return Clutter.EVENT_PROPAGATE;
+
+        this._touchSequence = event.get_event_sequence();
+
+        this._buttonDown = true;
+        this._grabActor();
+
+        let [stageX, stageY] = event.get_coords();
+        this._dragStartX = stageX;
+        this._dragStartY = stageY;
+
+        return Clutter.EVENT_PROPAGATE;
+    },
+
+    _grabDevice: function(actor) {
+        let manager = Clutter.DeviceManager.get_default();
+        let pointer = manager.get_core_device(Clutter.InputDeviceType.POINTER_DEVICE);
+
+        if (pointer && this._touchSequence)
+            pointer.sequence_grab(this._touchSequence, actor);
+        else if (pointer)
+            pointer.grab (actor);
+
+        this._grabbedDevice = pointer;
+    },
+
+    _ungrabDevice: function() {
+        if (this._touchSequence)
+            this._grabbedDevice.sequence_ungrab (this._touchSequence);
+        else
+            this._grabbedDevice.ungrab();
+
+        this._touchSequence = null;
+        this._grabbedDevice = null;
+    },
+
     _grabActor: function() {
-        Clutter.grab_pointer(this.actor);
+        this._grabDevice(this.actor);
         this._onEventId = this.actor.connect('event',
                                              Lang.bind(this, this._onEvent));
     },
@@ -131,7 +176,7 @@ const _Draggable = new Lang.Class({
         if (!this._onEventId)
             return;
 
-        Clutter.ungrab_pointer();
+        this._ungrabDevice();
         this.actor.disconnect(this._onEventId);
         this._onEventId = null;
     },
@@ -140,13 +185,13 @@ const _Draggable = new Lang.Class({
         if (!this._eventsGrabbed) {
             this._eventsGrabbed = Main.pushModal(_getEventHandlerActor());
             if (this._eventsGrabbed)
-                Clutter.grab_pointer(_getEventHandlerActor());
+                this._grabDevice(_getEventHandlerActor());
         }
     },
 
     _ungrabEvents: function() {
         if (this._eventsGrabbed) {
-            Clutter.ungrab_pointer();
+            this._ungrabDevice();
             Main.popModal(_getEventHandlerActor());
             this._eventsGrabbed = false;
         }
@@ -157,7 +202,9 @@ const _Draggable = new Lang.Class({
         // didn't start the drag, to drop the draggable in case the drag was in progress, and
         // to complete the drag and ensure that whatever happens to be under the pointer does
         // not get triggered if the drag was cancelled with Esc.
-        if (event.type() == Clutter.EventType.BUTTON_RELEASE) {
+        if (event.type() == Clutter.EventType.BUTTON_RELEASE ||
+            (event.type() == Clutter.EventType.TOUCH_END &&
+             global.display.is_pointer_emulating_sequence(event.get_event_sequence()))) {
             this._buttonDown = false;
             if (this._dragInProgress) {
                 return this._dragActorDropped(event);
@@ -172,7 +219,9 @@ const _Draggable = new Lang.Class({
             }
         // We intercept MOTION event to figure out if the drag has started and to draw
         // this._dragActor under the pointer when dragging is in progress
-        } else if (event.type() == Clutter.EventType.MOTION) {
+        } else if (event.type() == Clutter.EventType.MOTION ||
+                   (event.type() == Clutter.EventType.TOUCH_UPDATE &&
+                    global.display.is_pointer_emulating_sequence(event.get_event_sequence()))) {
             if (this._dragInProgress) {
                 return this._updateDragPosition(event);
             } else if (this._dragActor == null) {
@@ -214,7 +263,7 @@ const _Draggable = new Lang.Class({
      * This function is useful to call if you've specified manualMode
      * for the draggable.
      */
-    startDrag: function (stageX, stageY, time) {
+    startDrag: function (stageX, stageY, time, sequence) {
         currentDraggable = this;
         this._dragInProgress = true;
 
@@ -228,6 +277,8 @@ const _Draggable = new Lang.Class({
         this.emit('drag-begin', time);
         if (this._onEventId)
             this._ungrabActor();
+
+        this._touchSequence = sequence;
         this._grabEvents();
         global.screen.set_cursor(Meta.Cursor.DND_IN_DRAG);
 
@@ -338,8 +389,8 @@ const _Draggable = new Lang.Class({
         let threshold = Gtk.Settings.get_default().gtk_dnd_drag_threshold;
         if ((Math.abs(stageX - this._dragStartX) > threshold ||
              Math.abs(stageY - this._dragStartY) > threshold)) {
-                this.startDrag(stageX, stageY, event.get_time());
-                this._updateDragPosition(event);
+            this.startDrag(stageX, stageY, event.get_time(), this._touchSequence);
+            this._updateDragPosition(event);
         }
 
         return true;